package com.mhc.suzuki.service.impl;

import com.alibaba.fastjson.JSON;
import com.mhc.suzuki.constant.BeMarriedEnum;
import com.mhc.suzuki.constant.CustomerTypeEnum;
import com.mhc.suzuki.constant.EntityTypeEnum;
import com.mhc.suzuki.dal.model.*;
import com.mhc.suzuki.dal.query.*;
import com.mhc.suzuki.manager.*;
import com.mhc.suzuki.service.CarInfoService;
import com.mhc.suzuki.service.LoanInfoService;
import com.mhc.suzuki.service.ModifyService;
import com.mhc.suzuki.util.*;
import com.mhc.suzuki.vo.CarInfoVO;
import com.mhc.suzuki.vo.LoanInfoVO;
import com.mhc.suzuki.vo.ModifyHisVO;
import com.mhc.suzuki.vo.snapshot.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class ModifyServiceImpl<T> implements ModifyService<T> {

    @Autowired
    private CarInfoService carInfoService;
    @Autowired
    private LoanInfoService loanInfoService;
    @Autowired
    private ModifyHisManager modifyHisManager;
    @Autowired
    private CustomerManager customerManager;
    @Autowired
    private HouseInfoManager houseInfoManager;
    @Autowired
    private OrderCustomerRelManager orderCustomerRelManager;
    @Autowired
    private EmergencyContactManager emergencyContactManager;

    @Autowired
    private SnapshotManager snapshotManager;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createModify(Integer entityType, String bizRecId, Long staffId) {
        log.info("记录修改信息开始");
        Long start = System.currentTimeMillis();
        if (EntityTypeEnum.ORDER.getCode().equals(entityType)) {
            OrderSnapshotVO orderSnapshotVO = new OrderSnapshotVO();

            CarInfoVO carInfoVO = carInfoService.getCarInfo(bizRecId);
            if (carInfoVO != null) {
                orderSnapshotVO.setCarInfo(BeanCopierUtil.convert(carInfoVO, CarInfoSnapshotVO.class));
            }
            LoanInfoVO loanInfoVO = loanInfoService.getLoanInfo(bizRecId);
            if (loanInfoVO != null) {
                orderSnapshotVO.setLoanInfo(BeanCopierUtil.convert(loanInfoVO, LoanInfoSnapshotVO.class));
            }

            List<CustomerSnapshotVO> sponsorList = new ArrayList<>();
            OrderCustomerRelQuery orderCustomerRelQuery = new OrderCustomerRelQuery();
            orderCustomerRelQuery.createCriteria().andOrderNoEqualTo(bizRecId).andIsDeletedEqualTo(0);
            List<OrderCustomerRelDO> orderCustomerRelDOList = orderCustomerRelManager.selectByQuery(orderCustomerRelQuery);
            if (orderCustomerRelDOList != null && orderCustomerRelDOList.size() > 0) {
                orderCustomerRelDOList.forEach(orderCustomerRelDO -> {
                    CustomerDO customerDO = customerManager.selectByPrimaryKey(orderCustomerRelDO.getCustomerId());
                    CustomerSnapshotVO customerSnapshotVO = BeanCopierUtil.convert(customerDO, CustomerSnapshotVO.class);
                    customerSnapshotVO.setCustomerType(orderCustomerRelDO.getCustomerType());
                    customerSnapshotVO.setOrderNo(bizRecId);
                    //主贷人
                    if (CustomerTypeEnum.BUYER.getCode().equals(orderCustomerRelDO.getCustomerType())) {
                        HouseInfoQuery houseInfoQuery = new HouseInfoQuery();
                        houseInfoQuery.createCriteria().andCustomerIdEqualTo(orderCustomerRelDO.getCustomerId());
                        List<HouseInfoDO> houseInfoDOList = houseInfoManager.selectByQuery(houseInfoQuery);
                        if (houseInfoDOList != null && houseInfoDOList.size() > 0) {
                            BeanCopierUtil.copy(houseInfoDOList.get(0), customerSnapshotVO);
                        }

                        EmergencyContactQuery emergencyContactQuery = new EmergencyContactQuery();
                        emergencyContactQuery.createCriteria().andCustomerIdEqualTo(orderCustomerRelDO.getCustomerId());
                        List<EmergencyContactDO> emergencyContactDOList = emergencyContactManager.selectByQuery(emergencyContactQuery);
                        if (emergencyContactDOList != null && emergencyContactDOList.size() > 0) {
                            if(emergencyContactDOList.size()==2){
                                //联系人2
                                EmergencyContactDO emergencyContactDO1 = emergencyContactDOList.get(1);
                                customerSnapshotVO.setContact2Name(emergencyContactDO1.getName());
                                customerSnapshotVO.setContact2Mobilephone(emergencyContactDO1.getMobilephone());
                                customerSnapshotVO.setContact2Relationship(emergencyContactDO1.getRelationship());

                                //联系人1
                                EmergencyContactDO emergencyContactDO0 = emergencyContactDOList.get(0);
                                customerSnapshotVO.setContact1Name(emergencyContactDO0.getName());
                                customerSnapshotVO.setContact1Mobilephone(emergencyContactDO0.getMobilephone());
                                customerSnapshotVO.setContact1Relationship(emergencyContactDO0.getRelationship());

                            }else if(emergencyContactDOList.size()==1){
                                //联系人1
                                EmergencyContactDO emergencyContactDO0 = emergencyContactDOList.get(0);
                                customerSnapshotVO.setContact1Name(emergencyContactDO0.getName());
                                customerSnapshotVO.setContact1Mobilephone(emergencyContactDO0.getMobilephone());
                                customerSnapshotVO.setContact1Relationship(emergencyContactDO0.getRelationship());
                            }
                        }

                        orderSnapshotVO.setCustomerBuyerSnapshotVO(customerSnapshotVO);
                    }
                    //共同购车人
                    else if (CustomerTypeEnum.COMMONBUYER.getCode().equals(orderCustomerRelDO.getCustomerType())) {
                        orderSnapshotVO.setCustomerCommonBuyerSnapshotVO(customerSnapshotVO);
                    } else if (CustomerTypeEnum.SPONSOR.getCode().equals(orderCustomerRelDO.getCustomerType())) {
                        sponsorList.add(customerSnapshotVO);
                    }
                });

                if(sponsorList.size()==5){
                    orderSnapshotVO.setCustomerSponsorSnapshotVO5(sponsorList.get(4));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO4(sponsorList.get(3));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO3(sponsorList.get(2));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO2(sponsorList.get(1));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO1(sponsorList.get(0));
                }else if(sponsorList.size()==4){
                    orderSnapshotVO.setCustomerSponsorSnapshotVO4(sponsorList.get(3));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO3(sponsorList.get(2));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO2(sponsorList.get(1));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO1(sponsorList.get(0));
                } else if(sponsorList.size()==3){
                    orderSnapshotVO.setCustomerSponsorSnapshotVO3(sponsorList.get(2));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO2(sponsorList.get(1));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO1(sponsorList.get(0));
                 }else if(sponsorList.size()==2){
                    orderSnapshotVO.setCustomerSponsorSnapshotVO2(sponsorList.get(1));
                    orderSnapshotVO.setCustomerSponsorSnapshotVO1(sponsorList.get(0));
                }else if(sponsorList.size()==1){
                    orderSnapshotVO.setCustomerSponsorSnapshotVO1(sponsorList.get(0));
                }
            }

            this.addEntitySnapshot((T) orderSnapshotVO, EntityTypeEnum.ORDER.getCode(), bizRecId);

            this.recordLastTwoSnapshotModify(bizRecId, EntityTypeEnum.ORDER.getCode(), staffId);
            Long end = System.currentTimeMillis();
            log.info("记录修改信息结束,总共花费:{} 毫秒", end - start);
        } else {
            log.info("不是订单快照类型");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addEntitySnapshot(T obj, Integer entityType, String bizRecId) {
        SnapshotDO snapshotDO = new SnapshotDO();
        snapshotDO.setEntityType(entityType);
        snapshotDO.setBizRecId(bizRecId);
        snapshotDO.setSnapshotContent(JSON.toJSONString(obj));
        snapshotManager.insertSelective(snapshotDO);
        log.info("新增快照:{}成功", JSON.toJSONString(snapshotDO));
    }


    /**
     * 购车人
     * @param action
     * @param actionObj
     * @param bizRecId
     * @param entityType
     * @param staffId
     * @param fieldName
     * @param oldMarriedCode 修改前的婚姻状态
     * @param newMarriedCode 修改后的婚姻状态
     */
    private void customerDeal(Integer action, Object actionObj, String bizRecId, Integer entityType, Long staffId,
                            String fieldName, Integer oldMarriedCode, Integer newMarriedCode) {
        if ("customerCommonBuyerSnapshotVO".equals(fieldName) || fieldName.startsWith("customerSponsorSnapshotVO")) {
            List<ModifyHisDO> list = new ArrayList<>();
            CustomerSnapshotVO customerCommonSnapshotVO = (CustomerSnapshotVO) actionObj;
            ModifyHisDO modifyHisDO1 = new ModifyHisDO();
            modifyHisDO1.setBizRecId(bizRecId);
            modifyHisDO1.setEntityType(entityType);
            modifyHisDO1.setStaffId(staffId);
            modifyHisDO1.setFieldName("customerName");
            if ("customerCommonBuyerSnapshotVO".equals(fieldName)) {
                modifyHisDO1.setFieldAlias("共同购车人姓名");
            } else if (fieldName.startsWith("customerSponsorSnapshotVO")) {
                modifyHisDO1.setFieldAlias("担保人姓名");
            }
            ModifyHisDO modifyHisDO2 = new ModifyHisDO();
            modifyHisDO2.setBizRecId(bizRecId);
            modifyHisDO2.setEntityType(entityType);
            modifyHisDO2.setStaffId(staffId);
            modifyHisDO2.setFieldName("idCard");
            if (action.equals(1)) {
                //删除
                modifyHisDO1.setOldValue(customerCommonSnapshotVO.getCustomerName());
                modifyHisDO1.setNewValue("");
                modifyHisDO2.setOldValue(customerCommonSnapshotVO.getIdCard());
                modifyHisDO2.setNewValue("");
            }else{
                //新增
                modifyHisDO1.setOldValue("");
                modifyHisDO1.setNewValue(customerCommonSnapshotVO.getCustomerName());
                modifyHisDO2.setOldValue("");
                modifyHisDO2.setNewValue(customerCommonSnapshotVO.getIdCard());
            }
            if ("customerCommonBuyerSnapshotVO".equals(fieldName)) {
                modifyHisDO2.setFieldAlias("共同购车人身份证号码");
            } else if (fieldName.startsWith("customerSponsorSnapshotVO")) {
                modifyHisDO2.setFieldAlias("担保人身份证号码");
            }
            ModifyHisDO modifyHisDO3 = new ModifyHisDO();
            modifyHisDO3.setBizRecId(bizRecId);
            modifyHisDO3.setEntityType(entityType);
            modifyHisDO3.setStaffId(staffId);

            ModifyHisDO modifyHisDO = new ModifyHisDO();
            modifyHisDO.setBizRecId(bizRecId);
            modifyHisDO.setEntityType(entityType);
            modifyHisDO.setStaffId(staffId);
            modifyHisDO.setOldValue("");
            modifyHisDO.setFieldName("action");
            modifyHisDO.setFieldAlias("人员动作");
            if ("customerCommonBuyerSnapshotVO".equals(fieldName)) {
                if (action.equals(1)) {
                    modifyHisDO.setNewValue("删除共同购车人");
                    modifyHisDO3.setOldValue(BeMarriedEnum.getBeMarriedEnum(oldMarriedCode).getName());
                    modifyHisDO3.setNewValue("");
                } else {
                    modifyHisDO.setNewValue("新增共同购车人");
                    modifyHisDO3.setOldValue("");
                    modifyHisDO3.setNewValue(BeMarriedEnum.getBeMarriedEnum(newMarriedCode).getName());
                }
                modifyHisDO3.setFieldName("bemarried");
                modifyHisDO3.setFieldAlias("婚姻状态");
            } else if (fieldName.startsWith("customerSponsorSnapshotVO")) {
                if (action.equals(1)) {
                    modifyHisDO.setNewValue("删除担保人");
                    modifyHisDO3.setNewValue("");
                    modifyHisDO3.setOldValue(customerCommonSnapshotVO.getRelationship());
                } else {
                    modifyHisDO.setNewValue("新增担保人");
                    modifyHisDO3.setOldValue("");
                    modifyHisDO3.setNewValue(customerCommonSnapshotVO.getRelationship());
                }
                modifyHisDO3.setFieldName("relationship");
                modifyHisDO3.setFieldAlias("关系");
            }
            list.add(modifyHisDO);
            list.add(modifyHisDO1);
            list.add(modifyHisDO2);
            list.add(modifyHisDO3);
            record(list);// 调用保存入库的方法.
        }
    }

    private void addModifyRecord(Object oldObj, Object newObj, String bizRecId, Integer entityType, Long staffId, String fieldName, Integer oldMarriedCode,Integer newMarriedCode) {
        if (oldObj == newObj) {
            return;// 如果两个对象相同直接退出
        }
        if (newObj == null) {
            //如果没有新的对象,表示删除了记录,删除配偶,删除担保人等操作,
            log.debug("删除了记录,老的对象是:{}", JSON.toJSONString(oldObj));
            this.customerDeal(1, oldObj, bizRecId, entityType, staffId, fieldName, oldMarriedCode, newMarriedCode);
            return;
        }
        if (oldObj == null) {
            //如果没有老的对象,表示新增记录,新增配偶,增加担保人等操作,或者首次新增提交(只会处理 customer 中的记录)
            log.debug("新增了记录,老的对象是:{}", JSON.toJSONString(newObj));
            this.customerDeal(0, newObj, bizRecId, entityType, staffId, fieldName, oldMarriedCode, newMarriedCode);
            return;
        }
        if (JSON.toJSONString(oldObj).equals(JSON.toJSONString(newObj))) {
            return;
        }

        List<ModifyHisDO> list = new ArrayList<>();
        Field[] fields;
            fields = newObj.getClass().getDeclaredFields();// 得到指定类的所有属性Field.
        List<Field> allFields = new ArrayList<Field>();

        // 找出Id字段,便于记录
        for (Field field : fields) {
            field.setAccessible(true);// 设置类的私有字段属性可访问.
            // 设置了不记录变化的注解字段不记录变更历史.
            if (!field.isAnnotationPresent(HistoryNotRecord.class)) {
                allFields.add(field);
            }
            if (field.isAnnotationPresent(HistoryObject.class)) {
                addModifyRecord(ReflectUtils.getValue(oldObj, field.getName()), ReflectUtils.getValue(newObj, field.getName()), bizRecId, entityType, staffId, field.getName(), oldMarriedCode, newMarriedCode);
            }
        }

        // 比较实体对象的属性值,每个属性值不同的都新建一个History对象并保存入库.
        for (Field field : allFields) {
            if (field.isAnnotationPresent(HistoryObject.class)) {
                continue;
            }
            field.setAccessible(true);// 设置类的私有字段属性可访问.
            field.getAnnotation(HistoryAlias.class);

            try {
                if ((field.get(oldObj) == null) && (field.get(newObj) == null)) {
                    continue;
                }
                boolean oldIsNullAndNewIsNotNull = field.get(oldObj) == null && field.get(newObj) != null;
                if (oldIsNullAndNewIsNotNull || !field.get(oldObj).equals(field.get(newObj))) {
                    //todo 如果对象属于主贷人field.getName()是customerBuyerSnapshotVO,且身份证号码变化.说明更换主贷人了,记录更换主贷人几个字即可.其余变化不需要记录
                    // 如果对象属于共同购车人field.getName()customerCommonBuyerSnapshotVO,且身份证号码变化.说明更换主贷人了,记录更换主贷人几个字即可.其余变化不需要记录(同上,只需要记录一种就好)
                    // 如果是customerSponsorSnapshotVO1,本来没有,就显示增加担保人...显示变化增加字段:身份证,姓名,关系
                    if ("customerBuyerSnapshotVO".equals(fieldName) || "customerCommonBuyerSnapshotVO".equals(fieldName)) {
                        if ("customerId".equals(field.getName())) {
                            if (!field.get(newObj).equals(field.get(oldObj))) {
                                log.info("--更换主贷人操作--,理论上进入到这里来,只在上一步操作记录快照表就够了,不做差异比较");
                                //todo  这里是更换主贷人操作了.走的审核流程,需要显示更换原因
                                return;
                            }
                        }
                    }
                    ModifyHisDO history = new ModifyHisDO();
                    history.setEntityType(entityType);
                    history.setFieldName(field.getName());
                    if (field.isAnnotationPresent(HistoryAlias.class)) {
                        history.setFieldAlias(field
                                .getAnnotation(HistoryAlias.class).alias());
                    }
                    if (field.isAnnotationPresent(HistoryId.class)) {
                        history.setFieldAlias(field
                                .getAnnotation(HistoryId.class).alias());
                    }
                        history.setOldValue(String.valueOf(field.get(oldObj)).replace("null", ""));
                        history.setNewValue(String.valueOf(field.get(newObj)).replace("null", ""));
                    if (history.getOldValue().equals(history.getNewValue())) {
                        continue;
                    }

                    history.setBizRecId(bizRecId);// 记录修改的对象的主键Id.
                    history.setStaffId(staffId);
                    log.info("记录修改的记录:{}",JSON.toJSONString(history));
                    list.add(history);
                }
            } catch (IllegalArgumentException e) {
                log.error("IllegalArgumentException", e);
            } catch (IllegalAccessException e) {
                log.error("IllegalAccessException", e);
            }
        }
        record(list);// 调用保存入库的方法.
    }

    // 批量保存到数据库中,考虑到对象修改的属性可能较多,所以采用批量导入效率会高一些.
    private void record(List<ModifyHisDO> historys) {
        for (ModifyHisDO history : historys) {
            log.debug("插入的ModifyHis记录:{}",JSON.toJSONString(history));
            modifyHisManager.insertSelective(history);
        }
        log.info("处理后的记录:" + historys);
    }


    @Override
    public List<ModifyHisVO> queryModifyRecordList(String bizRecId, Integer entityType) {
        ModifyHisQuery query = new ModifyHisQuery();
        query.setOrderByClause("gmt_create desc");
        query.createCriteria().andBizRecIdEqualTo(bizRecId).andEntityTypeEqualTo(entityType);
        List<ModifyHisDO> modifyHisDOList = modifyHisManager.selectByQuery(query);
        List<ModifyHisVO> modifyHisVOList = new ArrayList<>();
        modifyHisDOList.forEach(modifyHisDO -> {
            ModifyHisVO modifyHisVO = BeanCopierUtil.convert(modifyHisDO, ModifyHisVO.class);
            modifyHisVOList.add(modifyHisVO);
        });

        return modifyHisVOList;
    }

    @Override
    public void recordLastTwoSnapshotModify(String bizRecId, Integer entityType, Long staffId) {
        SnapshotQuery query = new SnapshotQuery();
        query.setOrderByClause("gmt_create desc");
        query.createCriteria().andBizRecIdEqualTo(bizRecId).andEntityTypeEqualTo(entityType);
        List<SnapshotDO> snapshotDOList = snapshotManager.selectByQuery(query);

        if (snapshotDOList == null || snapshotDOList.size() < 2) {
            return;
        } else {
            SnapshotDO oldSnapshotDO = snapshotDOList.get(1);
            log.debug("老的记录是:{}", JSON.toJSONString(oldSnapshotDO));
            OrderSnapshotVO oldSnapshotVO = JSON.parseObject(oldSnapshotDO.getSnapshotContent(), OrderSnapshotVO.class);
            //-----------------------------------//
            SnapshotDO newSnapshotDO = snapshotDOList.get(0);
            log.debug("新的记录是:{}", JSON.toJSONString(newSnapshotDO));
            OrderSnapshotVO newSnapshotVO = JSON.parseObject(newSnapshotDO.getSnapshotContent(), OrderSnapshotVO.class);
            this.addModifyRecord(oldSnapshotVO, newSnapshotVO, bizRecId, entityType, staffId, "",
                    oldSnapshotVO.getCustomerBuyerSnapshotVO().getBemarried(),newSnapshotVO.getCustomerBuyerSnapshotVO().getBemarried());
        }
    }

}
